SpringMVC 响应数据
数据响应
这里就介绍直接返回数据的方法,至于视图那部分就跳过了,反正前后端分离之后也用不上
因为 SpringMVC 默认还是要走视图解析器,所以需要加上 @ResponseBody
注解,告诉 Spring 当前的 Service 跳过视图解析器,直接返回响应体
加上这个 @ResponseBody
注解后,return 的数据就是响应体的数据
前后端分离的核心,前端需要后端提供的数据,介质就是通过 json 来传输
所以 return 的数据就是 json,一般不需要手动将 java 对象转成 json 数据,正常开发都是使用一些第三方工具(例如 gson、fastjson、jackson)
Gson 自动返回 Json
导入依赖
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
Gson 的使用
private static final Gson gson = new Gson();
@GetMapping(value = "/json",produces = "text/json;charset=utf-8")
@ResponseBody
public String test2(){
User user = new User(1,"小红",20);
return gson.toJson(user);
}
集成到 Spring
通过添加对消息转换器 @ResponseBody
的配置可以达到自动配置编码以及自动把对象转换成 json 发送出去,无需手动处理
注意这个 message-converters 作用就是:配置一个或多个 HTTP 消息转换器来使用用于转换 @RequestBody
和 @ResponseBody
注解所修饰的 Controller 方法的返回值
实际就是 对注解解析添加一些工具(例如这里的消息转换器)
<!-- 配置这个注解驱动,如果直接使用 <mvc:annotation-driven> 则默认使用 jackson 来把对象转换成 json -->
<!-- 这个 <mvc:annotation-driven> 默认设置了很多东西,可以看上一篇的介绍 -->
<mvc:annotation-driven>
<!--之所以需要在这里配置是因为这个信息转换器是针对 @ResponseBody 注解的-->
<mvc:message-converters>
<!--json 乱码问题配置-->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="utf-8"/>
</bean>
<!--配置 json 映射的工具,这里使用 GSON-->
<bean class="org.springframework.http.converter.json.GsonHttpMessageConverter">
<property name="gson">
<bean class="com.google.gson.Gson"/>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
配置好 消息转换器 后就可以解放双手,直接传出对象自动生成 json 并自动转换为 utf-8
@GetMapping("/json")
@ResponseBody
public User test2(){
return new User(1,"小红",20);
}
甚至可以自动识别 List 生成数组
@GetMapping("/json")
@ResponseBody
public List<User> test2(){
List<User> users = new ArrayList<>();
users.add(new User(1,"小红",20));
users.add(new User(2,"艾达",30));
users.add(new User(3,"里昂",23));
return users;
}
ResponseEntity 工具类
参考资料 【SpringMVC(十三)】ResponseEntity 使用 及 原理
ResponseEntity 是什么
通常情况下,在前后端分离的大背景下,我们后台服务返回给前端的通常都是格式化的数据,比如 Json,开始的时候,我们用 json包生产一个 json的字符串,配合 http 协议的一些 API 来自定义实现,后来 SpringMVC 包装出来了通用的处理类 ResponseEntity
ResponseEntity 继承了 HttpEntity 类,HttpEntity 代表一个 http 请求或者响应实体,其内部有两个成员变量:header 及 body,代表 http 请求或响应的 header 及 body,其中的 body 是泛化的。
public class ResponseEntity<T> extends HttpEntity<T> {
private final Object status;
public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, HttpStatus status) {
super(body, headers);
Assert.notNull(status, "HttpStatus must not be null");
this.status = status;
}
// 省略其他代码
}
ResponseEntity 基本使用
@RequestMapping(value="/demo1" )
public ResponseEntity demo1(){
// 使用方式一.
ResponseEntity responseEntity = new ResponseEntity(new User("lvbb",24),HttpStatus.OK);
// 使用方式二.
return ResponseEntity.ok(new User("lvbb",24));
}
ResponseEntity 可以作为 controller 的返回值,比如对于一个处理下载二进制文件的接口,可以这么定义:
@RequestMapping("/download")
public ResponseEntity<byte[]> download(@RequestParam String fileName) throws IOException {
byte[] bytes = xxx;
return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
}
也可以使用流式风格的构造器:
@RequestMapping("/download")
public ResponseEntity<byte[]> download(@RequestParam String fileName) throws IOException {
byte[] bytes = xxx;
return ResponseEntity.ok()
.headers(headers)
.body(bytes);
}
ResponseEntity 不仅仅可以用于处理下载,非 ModelAndView 的其他场景均可以使用。在 WEB API 项目中,如果没有特定的 Java Bean 封装的返回类型,可以使用该类型。
与 @ResponseBody 的区别
使用 ResponseEntity 作为 controller 的返回值,我们可以方便地处理响应的 header,状态码以及 body。而通常使用的 @ResponseBody
注解,只能处理 body 部分。这也是为什么通常在下载场景中会使用 ResponseEntity,因为下载需要设置 header 里的 content-type 以及特殊的 status(比如206)。
ResponseEntity 的优先级高于 @ResponseBody
。在不是 ResponseEntity 的情况下才去检查有没有 @ResponseBody
注解。如果响应类型是ResponseEntity可以不写 @ResponseBody
注解,写了也没有关系。
简单粗暴的讲
@ResponseBody
可以直接返回 Json 结果- ResponseEntity 不仅可以返回 Json 结果,还可以定义返回的 HttpHeaders 和 HttpStatus
使用 ResponseEntity 自定义响应
使用这个 ResponseEntity 自定义 Restful 风格的响应内容
ResponseEntity 的用法(也是建造者模式)
ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
ResponseEntity.ok(list);
ResponseEntity.badRequest().build();
ResponseEntity.notFound().build();
创建 Result 类
创建一个 Result 类(建造者模式)
@Data
@Builder
public class Result<T> {
/**
* 业务码,比如成功、失败、权限不足等 code,可自行定义
*/
@ApiModelProperty("返回码")
private Integer code;
/**
* 返回信息,后端在进行业务处理后返回给前端一个提示信息,可自行定义
*/
@ApiModelProperty("返回信息")
private String message;
/**
* 数据结果,泛型,可以是列表、单个对象、数字、布尔值等
*/
@ApiModelProperty("返回数据")
private T data;
}
编写通用生成器工具类
再创建一个通用类型生成器,省的每次创建还需要手动设置状态码(对于复杂的返回类型依旧可以手动生成)
public final class ResultGeneratorUtils {
private ResultGeneratorUtils(){}
private static final String DEFAULT_SUCCESS_MESSAGE = "SUCCESS";
private static final int RESULT_CODE_SUCCESS = 200;
public static Result<String> genSuccessResult() {
return Result.<String>builder()
.code(RESULT_CODE_SUCCESS)
.message(DEFAULT_SUCCESS_MESSAGE)
.build();
}
public static Result<String> genSuccessResult(String message) {
return Result.<String>builder()
.code(RESULT_CODE_SUCCESS)
.message(message)
.build();
}
public static <T> Result<T> genSuccessResult(T data) {
return Result.<T>builder()
.code(RESULT_CODE_SUCCESS)
.message(DEFAULT_SUCCESS_MESSAGE)
.data(data)
.build();
}
public static <T> Result<T> genSuccessResult(String message, T data) {
return Result.<T>builder()
.code(RESULT_CODE_SUCCESS)
.message(message)
.data(data)
.build();
}
}
最后使用方式
@PreAuthorize("hasAnyRole('ROLE_ADMIN')")
@ApiOperation("说你好,需要 ADMIN 权限")
@GetMapping("/hello")
public ResponseEntity<Result<String>> sayHello() {
return ResponseEntity
.ok()
.body(ResultGeneratorUtils.genSuccessResult("你好,你能看到这条内容表示权限系统差不多了"));
}